Imports System.Threading
Imports bikisoft.datastream

Friend Class Consult
    Inherits Threads.BikiThread
    Private m_consultRet As Consult_Args
    Private m_status As String = ""
    Private m_integrated As streamType = streamType.STREAM_INTEGRATED
    Private WithEvents m_Commhandler As Comm.UsbCommunicationHandle = Nothing
    Private m_TimeoutCounter As Integer = 0
    Dim m_timer As New System.Timers.Timer(500)

    Friend Enum ByteRead As Byte
        BY_TRUE = 0
        BY_FALSE = 1
        BY_NODATA = 3
    End Enum

    Friend Enum ConsultBytes As ULong
        CB_RPM_HI = &H0
        CB_RPM_LO = &H1
        CB_AFM_HI = &H4
        CB_AFM_LO = &H5
        CB_TEMP = &H8
        CB_LH_O2 = &H9
        CB_RH_O2 = &HA
        CB_SPEED = &HB
        CB_BVOLT = &HC
        CB_TPS = &HD
        CB_LOAD = &HF
        CB_VETRACE = &H10
        CB_DBR1 = &H13
        CB_INJ_HI = &H14
        CB_INJ_LO = &H15
        CB_IGN = &H16
        CB_AAC = &H17
        CB_DCR1 = &H1E
        CB_DCR2 = &H1F
    End Enum

#Region "   Internal Structues for decoding the Data Stream"
    Public Const TRIGGER_COUNT As Byte = 32
    Public Const CONSULT_BYTES As Byte = 18
    Public Const AD_INPUTS_CNT As Byte = 3
    Public Const SWITCH_CNT As Byte = 6
    Public Const OUTPUT_CNT As Byte = 5
    Public Const SWADC_CNT As Byte = 8
    Friend Structure _typSwAdcInput
        Dim OnOff As Byte()
        Dim value As UInt16()
        Dim version As Boolean
        Dim mult As Double
        Sub Initialise(ByRef _Array As Byte(), ByRef Offset As Integer, ByVal handler As Comm.UsbCommunicationHandle)
            If _Array(0) >= &H1B Then
                mult = &HFFC0 / handler.UsbInformation.ADCMax
                version = True
                Dim cnt As Integer = 0
                ReDim OnOff(SWADC_CNT - SWITCH_CNT - 1)
                ReDim value(SWADC_CNT - AD_INPUTS_CNT - 1)
                For i As Integer = 0 To UBound(OnOff)
                    OnOff(i) = _Array(Offset)
                    Offset += 1
                    cnt += 1
                Next
                For i As Integer = 0 To UBound(value)
                    value(i) = System.BitConverter.ToUInt16(_Array, Offset)
                    Offset += 2
                    cnt += 1
                Next
                'Console.WriteLine("Lenth INSIDE: " & Offset & "  " & cnt)
            Else
                version = False
            End If
        End Sub
        Sub ToArgs(ByRef Args As Consult_Args, ByVal Num As Byte)
            ' do nothing
        End Sub
        Sub ToArgs(ByRef Args As DataStream.Stream, ByVal Num As Byte)
            If version Then
                For i As Integer = AD_INPUTS_CNT To SWADC_CNT - 1
                    Args.Add(New StreamItem("ADC" & i + 1, StreamItemType.mVolts, value(i - AD_INPUTS_CNT) / mult))
                Next
                For i As Integer = SWITCH_CNT To SWADC_CNT - 1
                    Args.Add(New StreamItem("SW" & i + 1, StreamItemType.Switch, OnOff(i - SWITCH_CNT)))
                Next
            End If
        End Sub
    End Structure
    Friend Structure _typAdInput
        Dim Raw As UInt16
        Dim Lookup As Single
        Dim Bits As Byte
        Dim Mult As Double
        Sub Initialise(ByRef _Array As Byte(), ByRef Offset As Integer, ByVal handler As Comm.UsbCommunicationHandle)
            Raw = System.BitConverter.ToUInt16(_Array, pp(Offset, 2))
            Lookup = System.BitConverter.ToSingle(_Array, pp(Offset, 4))
            Bits = _Array(pp(Offset))

            If _Array(0) >= &H1B Then
                Mult = &HFFC0 / handler.UsbInformation.ADCMax
            Else
                Mult = 0.2
            End If
        End Sub
        Sub ToArgs(ByRef Args As Consult_Args, ByVal Num As Byte)
            Args.ADClookup(Num) = Lookup
            Args.setAD(Raw, Num)
        End Sub
        Sub ToArgs(ByRef Args As DataStream.Stream, ByVal Num As Byte)
            Args.Add(New StreamItem("ADC" & Num, StreamItemType.mVolts, Raw / Mult))
            Args.Add(New StreamItem("ADC Lookup " & Num, StreamItemType.ADLookup, Lookup))
        End Sub
    End Structure
    Friend Structure _typSwInput
        Dim value As Byte
        Dim bounce As Byte
        Sub Initialise(ByRef _Array As Byte(), ByRef Offset As Integer)
            value = _Array(pp(Offset))
            bounce = _Array(pp(Offset))
        End Sub
        Sub ToArgs(ByRef Args As Consult_Args, ByVal Num As Byte)
            Args.setSWI(value, Num)
        End Sub
        Sub ToARgs(ByRef Args As DataStream.Stream, ByVal Num As Byte)
            Args.Add(New StreamItem("SW" & Num, StreamItemType.Switch, value))
        End Sub
    End Structure
    Friend Structure _typOutput
        Dim OnOff As Byte
        Dim Value As Single
        Sub Initialise(ByRef _Array As Byte(), ByRef Offset As Integer)
            OnOff = _Array(pp(Offset))
            Value = System.BitConverter.ToSingle(_Array, pp(Offset, 4))
        End Sub
        Sub ToArgs(ByRef Args As Consult_Args, ByVal Num As Byte)
            Args.setBKO(Value * 100, Num)
            Args.BKO_OnOff(Num) = OnOff
        End Sub
        Sub ToARgs(ByRef Args As DataStream.Stream, ByVal Num As Byte)
            Args.Add(New StreamItem("Aux" & Num, StreamItemType.AuxilaryOutput, Value * 100))
            Args.Add(New StreamItem("Aux" & Num & "State", StreamItemType.Switch, OnOff))
        End Sub
    End Structure
    Friend Structure _typConsult
        Dim BitSet As UInt32
        Dim Packet() As Byte
        Dim RPM As UInt16
        Dim AFM As UInt16
        Dim TPS As Byte
        Dim MAP As UInt16
        Dim SPEED As Byte
        Dim TEMP As Byte
        Dim LOAD As Byte
        Dim INJ As UInt16
        Dim IGN As Byte
        Dim BVOLTS As Byte
        Sub Initialise(ByRef _Array As Byte(), ByRef Offset As Integer)
            BitSet = System.BitConverter.ToUInt32(_Array, pp(Offset, 4))
            ReDim Packet(CONSULT_BYTES - 1)
            Array.Copy(_Array, pp(Offset, CONSULT_BYTES), Packet, 0, CONSULT_BYTES)
            RPM = System.BitConverter.ToUInt16(_Array, pp(Offset, 2))
            AFM = System.BitConverter.ToUInt16(_Array, pp(Offset, 2))
            TPS = _Array(pp(Offset))
            MAP = System.BitConverter.ToUInt16(_Array, pp(Offset, 2))
            SPEED = _Array(pp(Offset))
            TEMP = _Array(pp(Offset))
            LOAD = _Array(pp(Offset))
            INJ = System.BitConverter.ToUInt16(_Array, pp(Offset, 2))
            IGN = _Array(pp(Offset))
            BVOLTS = _Array(pp(Offset))
        End Sub
        Sub ToArgs(ByRef Args As Consult_Args)
            If BitSet > 0 AndAlso Packet(0) = &HFF AndAlso Packet(1) > 0 Then
                For i As UInt16 = 0 To Packet(1)
                    Select Case decodeConsultBitSet(BitSet, i)
                        Case ConsultBytes.CB_AAC
                            Args.setAac(Packet(i + 2))
                        Case ConsultBytes.CB_AFM_HI
                            Args.setAFM(((Args.getAFM() And &HFF) Or (CUShort(Packet(i + 2)) * &H100)))
                        Case ConsultBytes.CB_AFM_LO
                            Args.setAFM((Args.getAFM() And &HFF00) Or Packet(i + 2))
                        Case ConsultBytes.CB_BVOLT
                            Args.setBVoltage(Packet(i + 2))
                        Case ConsultBytes.CB_DBR1
                            Args.setRegister1(Packet(i + 2))
                        Case ConsultBytes.CB_DCR1
                            Args.setRegister2(Packet(i + 2))
                        Case ConsultBytes.CB_DCR2
                            Args.setRegister3(Packet(i + 2))
                        Case ConsultBytes.CB_IGN
                            Args.setIgnition(Packet(i + 2))
                        Case ConsultBytes.CB_INJ_HI
                            Args.setInjector(((Args.getInjector() And &HFF) Or (CUShort(Packet(i + 2)) * &H100)))
                        Case ConsultBytes.CB_INJ_LO
                            Args.setInjector((Args.getInjector() And &HFF00) Or Packet(i + 2))
                        Case ConsultBytes.CB_LH_O2
                            Args.setO2Left(Packet(i + 2))
                        Case ConsultBytes.CB_LOAD
                            Args.setTP(Packet(i + 2))
                        Case ConsultBytes.CB_RPM_HI
                            Args.setRPM(((Args.getRPM() And &HFF) Or (CUShort(Packet(i + 2)) * &H100)))
                        Case ConsultBytes.CB_RPM_LO
                            Args.setRPM((Args.getRPM() And &HFF00) Or Packet(i + 2))
                        Case ConsultBytes.CB_SPEED
                            Args.setSpeed(Packet(i + 2))
                        Case ConsultBytes.CB_TEMP
                            Args.setTemp(Packet(i + 2))
                        Case ConsultBytes.CB_TPS
                            Args.setTps(Packet(i + 2))
                        Case ConsultBytes.CB_VETRACE
                            Args.VeTrace = Packet(i + 2)
                    End Select
                Next
            End If
        End Sub
        Public Sub ToArgs(ByRef Stream As DataStream.Stream)
            Dim dataByte As Byte

            If BitSet > 0 AndAlso Packet(0) = &HFF AndAlso Packet(1) > 0 Then
                For i As UInt16 = 0 To Packet(1)
                    dataByte = Packet(i + 2)
                    Select Case decodeConsultBitSet(BitSet, i)
                        Case ConsultBytes.CB_AAC
                            Stream.Add(New StreamItem("AAC", StreamItemType.Percent, dataByte))
                        Case ConsultBytes.CB_AFM_HI
                            Stream.Add(New StreamItem("AFM", StreamItemType.mVolts, dataByte * &H500))
                        Case ConsultBytes.CB_AFM_LO
                            If Stream.Contains("AFM") Then
                                Stream("AFM").SetValue(Stream("AFM").Value + (dataByte * 5))
                            End If
                        Case ConsultBytes.CB_BVOLT
                            Stream.Add(New StreamItem("BVolts", StreamItemType.Volts, dataByte * 80))
                        Case ConsultBytes.CB_DBR1
                            Stream.Add(New StreamItem("Aircon Sw", StreamItemType.Switch, BitIsSet(dataByte, 4)))
                            Stream.Add(New StreamItem("Pw Steering Sw", StreamItemType.Switch, BitIsSet(dataByte, 3)))
                            Stream.Add(New StreamItem("Park Neautral Sw", StreamItemType.Switch, BitIsSet(dataByte, 2)))
                            Stream.Add(New StreamItem("Start Sw", StreamItemType.Switch, BitIsSet(dataByte, 1)))
                            Stream.Add(New StreamItem("Throttle Sw", StreamItemType.Switch, BitIsSet(dataByte, 0)))
                        Case ConsultBytes.CB_DCR1
                            Stream.Add(New StreamItem("Aircon Relay", StreamItemType.Switch, BitIsSet(dataByte, 7)))
                            Stream.Add(New StreamItem("Fuel Pump Relay", StreamItemType.Switch, BitIsSet(dataByte, 6)))
                            Stream.Add(New StreamItem("VCT Solenoid", StreamItemType.Switch, BitIsSet(dataByte, 5)))
                            Stream.Add(New StreamItem("Fan Hi Relay", StreamItemType.Switch, BitIsSet(dataByte, 1)))
                            Stream.Add(New StreamItem("Fan Lo Relay", StreamItemType.Switch, BitIsSet(dataByte, 0)))
                        Case ConsultBytes.CB_DCR2
                            Stream.Add(New StreamItem("PReg Control Valve", StreamItemType.Switch, BitIsSet(dataByte, 6)))
                            Stream.Add(New StreamItem("Wastegate Solenoid", StreamItemType.Switch, BitIsSet(dataByte, 5)))
                            Stream.Add(New StreamItem("IACV Solenoid", StreamItemType.Switch, BitIsSet(dataByte, 3)))
                            Stream.Add(New StreamItem("EGR Solenoid", StreamItemType.Switch, BitIsSet(dataByte, 0)))
                        Case ConsultBytes.CB_IGN
                            Stream.Add(New StreamItem("Ignition Timing", StreamItemType.Ignition, CInt(110) - dataByte))
                        Case ConsultBytes.CB_INJ_HI
                            Stream.Add(New StreamItem("Injector PW", StreamItemType.PulseWidth, dataByte * 2.56))
                        Case ConsultBytes.CB_INJ_LO
                            If Stream.Contains("Injector PW") Then
                                Stream("Injector PW").SetValue(Stream("Injector PW").Value + (dataByte / 100))
                            Else
                                Stream.Add(New StreamItem("Injector PW", StreamItemType.PulseWidth, dataByte / 100))
                            End If
                        Case ConsultBytes.CB_LH_O2
                            Stream.Add(New StreamItem("O2 Sensor (narrowband)", StreamItemType.mVolts, dataByte * 10))
                        Case ConsultBytes.CB_LOAD
                            Stream.Add(New StreamItem("Load", StreamItemType.Load, dataByte))
                        Case ConsultBytes.CB_RPM_HI
                            Stream.Add(New StreamItem("RPM", StreamItemType.RPM, dataByte * &H100 * 12.5))
                        Case ConsultBytes.CB_RPM_LO
                            If Stream.Contains("RPM") Then
                                Stream("RPM").SetValue(Stream("RPM").Value + (dataByte * 12.5))
                            Else
                                Stream.Add(New StreamItem("RPM", StreamItemType.RPM, dataByte))
                            End If
                        Case ConsultBytes.CB_SPEED
                            Stream.Add(New StreamItem("Speed", StreamItemType.Speed, dataByte * 2))
                        Case ConsultBytes.CB_TEMP
                            Stream.Add(New StreamItem("Temp", StreamItemType.TEMP, CInt(dataByte) - 50))
                        Case ConsultBytes.CB_TPS
                            Stream.Add(New StreamItem("TPS", StreamItemType.mVolts, dataByte * 20))
                        Case ConsultBytes.CB_VETRACE
                            Stream.Add(New StreamItem("VE", StreamItemType.Volts, dataByte))
                    End Select
                Next
            End If
        End Sub
    End Structure
    Friend Structure _typTraceData
        Dim Address As UInt32
        Dim Data As Byte()
    End Structure
    Friend Structure _typGlobalData
        Dim Consult As _typConsult
        Dim AdInputs() As _typAdInput
        Dim SwInputs() As _typSwInput
        Dim Outputs() As _typOutput
        Dim Triggers() As Byte
        Dim TriggersNew As UInt32
        Dim FlashMap As Byte
        Dim SwAdcInputs As _typSwAdcInput
        Dim CPUTime As Single
        Dim TraceData As _typTraceData
        Sub Initialise(ByRef _Array As Byte(), ByVal Offset As Integer, ByVal handler As Comm.UsbCommunicationHandle)
            ReDim AdInputs(AD_INPUTS_CNT - 1)
            ReDim SwInputs(SWITCH_CNT - 1)
            ReDim Outputs(OUTPUT_CNT - 1)
            Consult.Initialise(_Array, Offset)
            For i As Byte = 0 To AdInputs.Length - 1
                AdInputs(i).Initialise(_Array, Offset, handler)
            Next
            'Console.WriteLine("---------------------------")
            'Console.WriteLine("Lenth1: " & Offset)
            For i As Byte = 0 To SwInputs.Length - 1
                SwInputs(i).Initialise(_Array, Offset)
            Next
            'Console.WriteLine("Lenth2: " & Offset)
            For i As Byte = 0 To Outputs.Length - 1
                Outputs(i).Initialise(_Array, Offset)
            Next
            'Console.WriteLine("Lenth3: " & Offset)
            If _Array(0) >= &H1B Then
                Triggers = Nothing
                TriggersNew = System.BitConverter.ToUInt32(_Array, pp(Offset, 4))
            Else
                ReDim Triggers(TRIGGER_COUNT - 1)
                Array.Copy(_Array, pp(Offset, TRIGGER_COUNT), Triggers, 0, TRIGGER_COUNT)
            End If

            'Console.WriteLine("Lenth4: " & Offset)
            FlashMap = _Array(pp(Offset))
            'Console.WriteLine("Lenth5: " & Offset)
            SwAdcInputs.Initialise(_Array, Offset, handler)
            'Console.WriteLine("Lenth6: " & Offset)
            CPUTime = System.BitConverter.ToSingle(_Array, pp(Offset, 4))
            Offset += 6
            'Console.WriteLine("Lenth7: " & Offset)

            If _Array(0) >= &H1C Then
                TraceData.Address = System.BitConverter.ToUInt16(_Array, pp(Offset, 2)) * 2
                ReDim TraceData.Data(15)
                Array.Copy(_Array, pp(Offset, 16), TraceData.Data, 0, 16)
                'Console.WriteLine(cv_HexFromBytes(TraceData.Data))
            End If

        End Sub
        Sub ToArgs(ByRef Args As Consult_Args)
            Consult.ToArgs(Args)
            For i As Byte = 0 To Outputs.Length - 1
                Outputs(i).ToArgs(Args, i)
            Next
            For i As Byte = 0 To SwInputs.Length - 1
                SwInputs(i).ToArgs(Args, i)
            Next
            For i As Byte = 0 To AdInputs.Length - 1
                AdInputs(i).ToArgs(Args, i)
            Next
            If Not Triggers Is Nothing Then
                For i As Byte = 0 To Triggers.Length - 1
                    Args.setTrigger(Triggers(i), i)
                Next
            Else
                For i As Byte = 0 To TRIGGER_COUNT
                    Args.setTrigger((TriggersNew >> i) And &H1, i)
                Next
            End If
            Args.CPUTime = CPUTime
        End Sub
        Sub ToArgs(ByRef Stream As DataStream.Stream)
            Try
                Consult.ToArgs(Stream)
            Catch ex As Exception

            End Try

            For i As Byte = 1 To Outputs.Length
                Outputs(i - 1).ToArgs(Stream, i)
            Next
            For i As Byte = 1 To SwInputs.Length
                SwInputs(i - 1).ToArgs(Stream, i)
            Next
            For i As Byte = 1 To AdInputs.Length
                AdInputs(i - 1).ToArgs(Stream, i)
            Next

            If Not Triggers Is Nothing Then
                For i As Byte = 1 To Triggers.Length
                    Stream.Add(New DataStream.StreamItem("TR" & i, StreamItemType.Switch, Triggers(i - 1)))
                Next
            Else
                For i As Byte = 1 To TRIGGER_COUNT
                    Stream.Add(New DataStream.StreamItem("TR" & i, StreamItemType.Switch, (TriggersNew >> (i - 1)) And &H1))
                Next
            End If

            SwAdcInputs.ToArgs(Stream, 0)
            Stream.Add(New DataStream.StreamItem("CPU Usage", StreamItemType.Percent, Me.CPUTime))
            Stream.Add(New DataStream.StreamItem("Flash Map", StreamItemType.Number, Me.FlashMap))

            Dim adrs(255) As Double
            Dim cnt As Integer = 0
            For i As Integer = 0 To Me.TraceData.Data.Length - 1
                For x As Integer = 0 To 7
                    If Me.TraceData.Data(i) And 1UI << x Then
                        adrs(cnt) = Me.TraceData.Address + (i * 16) + (x * 2)
                        adrs(cnt + 1) = Me.TraceData.Address + (i * 16) + (x * 2) + 1
                        cnt += 2
                    End If
                Next
            Next
            If cnt Then
                ReDim Preserve adrs(cnt - 1)
                Stream.Add(New DataStream.StreamItem("EmulatorAddress", StreamItemType.Hidden, adrs))
            Else
                'ReDim Preserve adrs(4)
                'adrs(0) = Me.TraceData.Address + (Now.Second / 4)
                'adrs(1) = Me.TraceData.Address + 1 + (Now.Second / 4)
                'adrs(2) = Me.TraceData.Address + 16 + (Now.Second / 4)
                'adrs(3) = Me.TraceData.Address + 17 + (Now.Second / 4)
                'Stream.Add(New DataStream.StreamItem("EmulatorAddress", StreamItemType.Hidden, adrs))
            End If

        End Sub
    End Structure
#End Region

    Friend Event Stream(ByVal sender As Object, ByVal e As ConsultEventArgs)

    Sub New(ByRef CommHandler As Comm.UsbCommunicationHandle)
        m_Commhandler = CommHandler
        m_consultRet = New Consult_Args
    End Sub

    Friend Overloads Function Execute( _
                 ByVal backGroundWorker As System.ComponentModel.BackgroundWorker, _
                 ByVal e As System.ComponentModel.DoWorkEventArgs) As Boolean
        MyBase.Execute(backGroundWorker, e)


        AddHandler m_timer.Elapsed, AddressOf Re_Initialise

        If Not m_UsbCommHandler Is Nothing _
              AndAlso m_UsbCommHandler.IsConnected _
              AndAlso m_UsbCommHandler.Initialised Then
            AddHandler m_Commhandler.StreamDataEventHandler, AddressOf StreamRecieverEventHandler
            'Dim Handle As Integer
ReInit:     If InitialiseStream() Then
                ' Handle = Me.m_Commhandler.Handle
                OnMessage("+Data Stream Requested")
                While Not MyBase.bgw.CancellationPending
                    Threading.Thread.Sleep(1000)

                End While
            Else
                OnMessage("!Error Initialising Data Stream, Request for data stream failed")
            End If
            m_timer.Stop()

            RemoveHandler m_Commhandler.StreamDataEventHandler, AddressOf StreamRecieverEventHandler
            CloseStream(5)
        End If

        RemoveHandler m_timer.Elapsed, AddressOf Re_Initialise

        m_timer.Stop()
        m_timer.Dispose()

        Return True
    End Function

    Private Sub Re_Initialise(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)
        If Me.m_Commhandler.Initialised Then
            If InitialiseStream() = True Then
                OnMessage("Stream re_initialised")
            Else
                OnMessage("Stream initialse failed")
            End If
        End If
    End Sub

    ''' <summary>
    ''' Integrated BikiRom New stream
    ''' </summary>
    ''' <remarks></remarks>
    Private Function InitialiseStream() As Boolean
        Dim f_Frame As Comm.Comm_Frame

        Try
            m_Commhandler.Timeout = 1000

            m_timer.Stop()

            Debug.Print("Attempting to init stream")

            f_Frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_CONSULT_INTEGRATED, , Comm.Comm_Frame.BikiFrameAction.CMD_GO)
            m_Commhandler.SendFrame(f_Frame)

        Catch exComm As Comm_Exceptions
            Return False
        Catch exUsb As USB_exceptions
            Return False
        Finally
            Try
                m_timer.Start()
            Catch ex As Exception

            End Try

        End Try

        Return True
    End Function

    Private Function CloseStream(Optional ByVal repeat As Integer = 0) As Boolean
        Dim f_Frame As Comm.Comm_Frame

        Try

            f_Frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_CONSULT_INTEGRATED, , Comm.Comm_Frame.BikiFrameAction.CMD_STOP)
            m_Commhandler.SendFrame(f_Frame)

        Catch exComm As Comm_Exceptions
            If repeat Then
                repeat -= 1
                Return CloseStream(repeat)
            End If
            Return False
        Catch exUsb As USB_exceptions
            Return False
        End Try

        Return True
    End Function

    Private Sub StreamRecieverEventHandler(ByVal sender As Object, ByVal e As Comm.UsbDataEventArguments)
        If m_TimeoutCounter = -1 Then
            OnMessage("=Stream Initialised Successfuly.. streaming..")
        End If
        m_TimeoutCounter = 0
        m_timer.Stop()
        m_timer.Start()
        'Debug.Print("Stream Event!")
        'RemoveHandler m_Commhandler.StreamDataEventHandler, AddressOf StreamRecieverEventHandler
        RaiseEvent Stream(Me, New ConsultEventArgs(decodeStream(e.Data.Data)))
        ' AddHandler m_Commhandler.StreamDataEventHandler, AddressOf StreamRecieverEventHandler
    End Sub

    Friend Function decodeStream(ByRef Data As Byte()) As DataStream.Stream
        Dim stream As New DataStream.Stream
        ' set the streams data..
        Dim f_Data(Data.Length - 12) As Byte
        Dim f_BitSet As ULong = 0
        Dim nPt As Integer = 0
        Dim dataByte As Byte
        Array.Copy(Data, 7, f_Data, 0, Data.Length - 11)
        If f_Data(0) = 0 Then
            f_BitSet = CULng(f_Data(0)) << 40
            f_BitSet += CULng(f_Data(1)) << 32
            f_BitSet += CULng(f_Data(2)) << 24
            f_BitSet += CULng(f_Data(3)) << 16
            f_BitSet += CULng(f_Data(4)) << 8
            f_BitSet += CULng(f_Data(5))

            If f_BitSet > 0 AndAlso f_Data(6) = &HFF AndAlso f_Data(7) > 0 Then
                For i As UInt16 = 0 To f_Data(7)
                    dataByte = f_Data(8 + i)
                    Select Case decodeConsultBitSet(f_BitSet, i)
                        Case ConsultBytes.CB_AAC
                            stream.Add(New StreamItem("AAC", StreamItemType.Percent, dataByte))
                        Case ConsultBytes.CB_AFM_HI
                            stream.Add(New StreamItem("AFM", StreamItemType.Percent, dataByte * &H500))
                        Case ConsultBytes.CB_AFM_LO
                            If stream.contains("AFM") Then
                                stream("AFM").SetValue(stream("AFM").Value + (dataByte * 5))
                            End If
                        Case ConsultBytes.CB_BVOLT
                            stream.Add(New StreamItem("BVolts", StreamItemType.Volts, dataByte * 80))
                        Case ConsultBytes.CB_DBR1
                            stream.Add(New StreamItem("Aircon Sw", StreamItemType.Switch, BitIsSet(dataByte, 4)))
                            stream.Add(New StreamItem("Pw Steering Sw", StreamItemType.Switch, BitIsSet(dataByte, 3)))
                            stream.Add(New StreamItem("Park Neautral Sw", StreamItemType.Switch, BitIsSet(dataByte, 2)))
                            stream.Add(New StreamItem("Start Sw", StreamItemType.Switch, BitIsSet(dataByte, 1)))
                            stream.Add(New StreamItem("Throttle Sw", StreamItemType.Switch, BitIsSet(dataByte, 0)))
                        Case ConsultBytes.CB_DCR1
                            stream.Add(New StreamItem("Aircon Relay", StreamItemType.Switch, BitIsSet(dataByte, 7)))
                            stream.Add(New StreamItem("Fuel Pump Relay", StreamItemType.Switch, BitIsSet(dataByte, 6)))
                            stream.Add(New StreamItem("VCT Solenoid", StreamItemType.Switch, BitIsSet(dataByte, 5)))
                            stream.Add(New StreamItem("Fan Hi Relay", StreamItemType.Switch, BitIsSet(dataByte, 1)))
                            stream.Add(New StreamItem("Fan Lo Relay", StreamItemType.Switch, BitIsSet(dataByte, 0)))
                        Case ConsultBytes.CB_DCR2
                            stream.Add(New StreamItem("PReg Control Valve", StreamItemType.Switch, BitIsSet(dataByte, 6)))
                            stream.Add(New StreamItem("Wastegate Solenoid", StreamItemType.Switch, BitIsSet(dataByte, 5)))
                            stream.Add(New StreamItem("IACV Solenoid", StreamItemType.Switch, BitIsSet(dataByte, 3)))
                            stream.Add(New StreamItem("EGR Solenoid", StreamItemType.Switch, BitIsSet(dataByte, 0)))
                        Case ConsultBytes.CB_IGN
                            stream.Add(New StreamItem("Ignition Timing", StreamItemType.Ignition, CInt(110) - dataByte))
                        Case ConsultBytes.CB_INJ_HI
                            stream.Add(New StreamItem("Injector PW", StreamItemType.PulseWidth, dataByte * 2.56))
                        Case ConsultBytes.CB_INJ_LO
                            If stream.contains("Injector PW") Then
                                stream("Injector PW").SetValue(stream("Injector PW").Value + (dataByte / 100))
                            Else
                                stream.Add(New StreamItem("Injector PW", StreamItemType.PulseWidth, dataByte / 100))
                            End If
                        Case ConsultBytes.CB_LH_O2
                            stream.Add(New StreamItem("O2 Sensor (narrowband)", StreamItemType.mVolts, dataByte * 10))
                        Case ConsultBytes.CB_LOAD
                            stream.Add(New StreamItem("Load", StreamItemType.Load, dataByte))
                        Case ConsultBytes.CB_RPM_HI
                            stream.Add(New StreamItem("RPM", StreamItemType.RPM, dataByte * &H100 * 12.5))
                        Case ConsultBytes.CB_RPM_LO
                            If stream.contains("RPM") Then
                                stream("RPM").SetValue(stream("RPM").Value + (dataByte * 12.5))
                            Else
                                stream.Add(New StreamItem("RPM", StreamItemType.RPM, dataByte))
                            End If
                        Case ConsultBytes.CB_SPEED
                            stream.Add(New StreamItem("Speed", StreamItemType.Speed, dataByte * 2))
                        Case ConsultBytes.CB_TEMP
                            stream.Add(New StreamItem("Temp", StreamItemType.TEMP, CInt(dataByte) - 50))
                        Case ConsultBytes.CB_TPS
                            stream.Add(New StreamItem("TPS", StreamItemType.mVolts, dataByte * 20))
                        Case ConsultBytes.CB_VETRACE
                            stream.Add(New StreamItem("VE", StreamItemType.Volts, dataByte))
                    End Select
                Next
            End If

            ' Bikirom Board Variable Parsing
            stream.Add(New StreamItem("ADC1", StreamItemType.mVolts, (CUShort((f_Data(24)) * &H100) Or f_Data(25))))
            stream.Add(New StreamItem("ADC2", StreamItemType.mVolts, (CUShort((f_Data(26)) * &H100) Or f_Data(27))))
            stream.Add(New StreamItem("ADC3", StreamItemType.mVolts, (CUShort((f_Data(28)) * &H100) Or f_Data(29))))
            stream.Add(New StreamItem("SW1", StreamItemType.Switch, BitIsSet(f_Data(30), 0)))
            stream.Add(New StreamItem("SW2", StreamItemType.Switch, BitIsSet(f_Data(30), 1)))
            stream.Add(New StreamItem("SW3", StreamItemType.Switch, BitIsSet(f_Data(30), 2)))
            stream.Add(New StreamItem("SW4", StreamItemType.Switch, BitIsSet(f_Data(30), 3)))
            stream.Add(New StreamItem("SW5", StreamItemType.Switch, BitIsSet(f_Data(30), 4)))
            stream.Add(New StreamItem("Aux1", StreamItemType.Percent, (CUShort((f_Data(31)) * &H100) Or f_Data(32))))
            stream.Add(New StreamItem("Aux2", StreamItemType.Percent, (CUShort((f_Data(33)) * &H100) Or f_Data(34))))
            stream.Add(New StreamItem("Aux3", StreamItemType.Percent, (CUShort((f_Data(35)) * &H100) Or f_Data(36))))
            stream.Add(New StreamItem("Aux4", StreamItemType.Percent, (CUShort((f_Data(37)) * &H100) Or f_Data(38))))

            Dim triggers As ULong = System.BitConverter.ToUInt32(f_Data, 39)
            For i As Integer = 0 To 19
                stream.Add(New StreamItem("TR" & i, StreamItemType.Switch, BitIsSet(triggers, i)))
            Next
            'Args.setTrigger((CUInt(f_Data(39)) << 24) Or (CUInt(f_Data(40)) << 16) Or (CUInt(f_Data(41)) << 8) Or CUInt(f_Data(42)))
            For i As Integer = 0 To 2
                stream.Add(New StreamItem("ADC Lookup " & i, StreamItemType.ADLookup, System.BitConverter.ToSingle(f_Data, 51 + (4 * i))))
            Next
            'Args.setADCLU(New Object() {System.BitConverter.ToSingle(f_Data, 51), System.BitConverter.ToSingle(f_Data, 55), System.BitConverter.ToSingle(f_Data, 59)})
            stream.Add(New StreamItem("Flash Map", StreamItemType.AFR, f_Data(63)))
            stream.Add(New StreamItem("ALU", StreamItemType.Number, System.BitConverter.ToSingle(f_Data, 64)))
            'Args.setAUCalc(New Object() {CUShort(f_Data(64)) << 8 Or f_Data(65), CUShort(f_Data(66)) << 8 Or f_Data(67)})
            'Args.setRPM((CInt(f_Data(45)) << 8) Or f_Data(46))
            'Args.setAFM((CInt(f_Data(47)) << 8) Or f_Data(48))
            'Args.setTps(f_Data(49))
            'Args.setTemp(f_Data(50))
        ElseIf f_Data(0) >= &H15 Then
            Dim mGlobalData As New _typGlobalData
            mGlobalData.Initialise(f_Data, 1, Me.m_Commhandler)
            mGlobalData.ToArgs(stream)

        End If

        Return stream
    End Function

    ''' <summary>
    ''' Find the Consult byte in Position of the BitSet
    ''' </summary>
    ''' <param name="BitSet"></param>
    ''' <param name="Position"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Friend Shared Function decodeConsultBitSet(ByVal BitSet As UInt32, ByVal Position As Byte) As ConsultBytes
        Dim f_PosCount As UInt16 = 0
        For i As UInt16 = 0 To 32
            If (BitSet \ (2 ^ i)) And &H1 Then f_PosCount += 1
            If (f_PosCount - 1) = Position Then Return CType(i, ConsultBytes)
        Next
        Return &HFF
    End Function
End Class
